package hapi.ui;

import flash.MovieClip;
import hapi.event.Dispatcher;
import hapi.event.HapiDispatcher;
import hapi.event.Notifier;

enum ButtonState {
	up;
	down;
	over;
	disabled;
}

import hapi.ui.Button;
import hapi.ui.Pressable;
import hapi.ui.Rollable;

class FlashButton implements Button {
	
	public var onPress(getOnPress, null):Notifier<PressEvent>;
	public var onRelease(getOnRelease, null):Notifier<PressEvent>;
	public var onRollOver(default, null):Notifier<RollOverEvent>;
	public var onRollOut(default, null):Notifier<RollOutEvent>;
	
	var onPressDispatcher:HapiDispatcher<PressEvent>;
	var onReleaseDispatcher:HapiDispatcher<PressEvent>;
	var onRollOverDispatcher:HapiDispatcher<RollOverEvent>;
	var onRollOutDispatcher:HapiDispatcher<RollOutEvent>;
	
	var state:ButtonState;
	var skin:FlashButtonSkin;
	var enabled:Bool;
	var pressed:Bool;
	
	public function new(skin) {
		this.enabled = true;
		initSkin(skin);
		initDispatchers();
		changeState(ButtonState.up);
		addHandlers();
		pressed = false;
	}
	
	public function press() {
		skin.onPress();
		pressed = true;
	}
	
	public function release() {
		skin.onRelease();
		pressed = false;
	}
	
	public function isPressed() {
		return pressed;
	}
	
	private function initDispatchers() {
		onPressDispatcher = new HapiDispatcher();
		onReleaseDispatcher = new HapiDispatcher();
		onRollOut = onRollOutDispatcher = new HapiDispatcher();
		onRollOver = onRollOverDispatcher = new HapiDispatcher();
	}

	private function changeState(state:ButtonState) {
		skin.gotoAndPlay(state);
	}
	
	private function initSkin(skin) {
		this.skin = skin;
	}
	
	private function addHandlers() {
		skin.onRollOver = changeStageHandler( ButtonState.over, onRollOverDispatcher );
		skin.onRollOut = changeStageHandler( ButtonState.up, onRollOutDispatcher );
		skin.onPress = changeStageHandler( ButtonState.down, onPressDispatcher );
		skin.onRelease = changeStageHandler( ButtonState.over, onReleaseDispatcher );
		skin.onReleaseOutside = changeStageHandler( ButtonState.up, onReleaseDispatcher );
		skin.onDragOut = changeStageHandler( ButtonState.up );
	}
	
	private function removeHandlers() {
		Reflect.deleteField(skin, "onRollOver");
		Reflect.deleteField(skin, "onRollOut");
		Reflect.deleteField(skin, "onPress");
		Reflect.deleteField(skin, "onRelease");
		Reflect.deleteField(skin, "onReleaseOutside");
		Reflect.deleteField(skin, "onDragOut");
	}
	
	private function changeStageHandler( state:ButtonState, ?dispatcher:Dispatcher < Dynamic > ) {
		var self = this;
		var handler = 
			if( dispatcher == null) {
				function() {
					self.changeState( state );
				}
			}else {
				function() {
					self.changeState( state );
					dispatcher.dispatchEvent(cast { source:self });
				}
			}
		return handler;
	}
	
	public function enable() {
		if (!isEnabled()) {
			this.enabled = true;
			changeState(ButtonState.up);
			addHandlers();
		}
	} 
	
	public function disable() {
		if (isEnabled()) {
			changeState(ButtonState.disabled);
			this.enabled = false;
			removeHandlers();
		}
	} 
	
	public function isEnabled() {
		return this.enabled;
	}	
	
	function getOnPress() {
		return onPressDispatcher;
	}
	
	function getOnRelease() {
		return onReleaseDispatcher;
	}
}

typedef FlashButtonSkin = { > MovieClip,
}